﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WebCollection.Tags;
using System.Xml;
using System.Text.RegularExpressions;

namespace WebCollection
{
    internal class GatherRule
    {
        private List<TPage> pages = new List<TPage>();

        public string SeedUrl { get; set; }

        public TPage Match(string url)
        {
            foreach (TPage tp in pages)
            {
                if (tp.Regex.IsMatch(url))
                {
                    return tp;
                }
            }
            throw new Exception("match config failed：" + url);
        }

        public GatherRule(string filename)
        {
            XmlDocument xdoc = new XmlDocument();
            xdoc.Load(filename);
            XmlNodeList xnlPage = xdoc.SelectNodes("/template/page");
            if (xnlPage.Count == 0)
                throw new Exception("config err：not find page tag" + filename);
            foreach (XmlNode xnPage in xnlPage)
            {
                GetTPage(xnPage);
            }
            XmlNode xnSeed = xdoc.SelectSingleNode("/template/seed");
            SeedUrl = xnSeed.InnerText;
        }

        private void GetTPage(XmlNode xnPage)
        {
            string threads = xnPage.Attributes["threads"].Value;
            bool multiThreads = bool.Parse(threads);
            string strdynamic = xnPage.Attributes["dynamic"].Value;
            bool dynamic = bool.Parse(strdynamic);
            string des = xnPage.Attributes["desc"].Value;
            string pattern = xnPage.Attributes["pattern"].Value;
            Regex regex = new Regex(pattern);
            TEnqueue ten = GetTEnqueue(xnPage);
            TSave tsave = GetTSave(xnPage);
            TSave_M tsave_m = GetTSave_M(xnPage);
            TPage tp = new TPage(regex, des, multiThreads, dynamic, tsave, ten, tsave_m);
            pages.Add(tp);
        }

        private TSave_M GetTSave_M(XmlNode xnPage)
        {
            XmlNode xnSave_m = xnPage.SelectSingleNode("./save_m");
            if (xnSave_m == null) return null;
            XmlNode xnRoot = xnSave_m.Attributes["root"];
            string root = xnRoot == null ? "." : xnRoot.Value;
            XmlNode xnClassName = xnSave_m.Attributes["classname"];
            string classname = xnClassName.Value;//若保存多次 ClassName属性不能缺少

            List<TField> list = GetTFields(xnSave_m);

            TSave_M ts_m = new TSave_M(root, classname, list);
            return ts_m;
        }

        private TSave GetTSave(XmlNode xnPage)
        {
            XmlNode xnSave = xnPage.SelectSingleNode("./save");
            if (xnSave == null) return null;
            XmlNode xnRoot = xnSave.Attributes["root"];
            string root = xnRoot == null ? "." : xnRoot.Value;


            List<TField> list = GetTFields(xnSave);

            TSave ts = new TSave(root, list);
            return ts;
        }

        private List<TField> GetTFields(XmlNode xnSave)
        {
            XmlNodeList xnlField = xnSave.SelectNodes(@"./field");
            if (xnlField == null || xnlField.Count < 1) return null;
            List<TField> list = new List<TField>();
            foreach (XmlNode xnField in xnlField)
            {
                TField field = GetTField(xnField);
                list.Add(field);
            }
            return list;
        }

        private TField GetTField(XmlNode xnField)
        {
            XmlNode xnName = xnField.SelectSingleNode(@"./name");
            if (xnName == null) throw new Exception("not find name tag");

            XmlNode xnnewentry = xnField.Attributes["newentry"];
            string strnewentry = xnnewentry == null ? "nonentry" : xnnewentry.Value;
            Entry newentry = (Entry)Enum.Parse(typeof(Entry), strnewentry);

            string name = xnName.InnerText;

            TConst tc = GetTConst(xnField);

            TXPath tx = GetTXPath(xnField);

            TRegex tr = GetTRegex(xnField);

            TField tf = new TField(newentry, name, tc, tx, tr);
            return tf;
        }

        private TConst GetTConst(XmlNode xnField)
        {
            XmlNode xnConst = xnField.SelectSingleNode(@"./const");
            if (xnConst == null) return null;

            string econst = xnConst.InnerText;

            TValue tv = GetTValue(xnField);

            TConst tc = new TConst(econst, tv);

            return tc;
        }

        private TValue GetTValue(XmlNode xnField)
        {
            XmlNode xnValue = xnField.SelectSingleNode(@"./value");
            if (xnValue == null) return null;

            string value = xnValue.InnerText;
            TValue tv = new TValue(value);
            return tv;
        }

        private TRegex GetTRegex(XmlNode xnField)
        {
            XmlNode xnRegex = xnField.SelectSingleNode(@"./regex");
            if (xnRegex == null) return null;
            TPattern tp = GetTPattern(xnRegex);
            TFormat tf = GetTFormat(xnRegex);
            TRegex tr = new TRegex(tp, tf);
            return tr;
        }

        private TFormat GetTFormat(XmlNode xnRegex)
        {
            XmlNode xnFormat = xnRegex.SelectSingleNode(@"./format");
            if (xnFormat == null) return null;
            string format = xnFormat.InnerText;
            TFormat tf = new TFormat(format);
            return tf;
        }

        private TPattern GetTPattern(XmlNode xnRegex)
        {
            XmlNode xnPattern = xnRegex.SelectSingleNode(@"./pattern");
            if (xnPattern == null)
                throw new Exception("not find pattern tag");
            string pattern = xnPattern.InnerText;
            return new TPattern(pattern);
        }

        private TXPath GetTXPath(XmlNode xnField)
        {
            XmlNode xnXPath = xnField.SelectSingleNode(@"./xpath");
            if (xnXPath == null) return null;
            string xpath = xnXPath.InnerText;
            XmlNode xnPostion = xnXPath.Attributes["position"];
            string position = xnPostion == null ? "innertext" : xnPostion.Value;
            TXPath tx = new TXPath(xpath, position);
            return tx;
        }

        private TEnqueue GetTEnqueue(XmlNode xnPage)
        {
            XmlNode xnEnqueue = xnPage.SelectSingleNode(@"./enqueue");
            if (xnEnqueue == null) return null;


            XmlNodeList xnl = xnEnqueue.SelectNodes("./xpath");

            List<TXPath> list = new List<TXPath>();
            foreach (XmlNode xn in xnl)
            {
                string xpath = xn.InnerText;
                TXPath tp = new TXPath(xpath, null);
                list.Add(tp);
            }
            TEnqueue ten = new TEnqueue(list);
            return ten;
        }
    }
}
